package com.lwh.util;


import com.sun.istack.internal.NotNull;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Date;


/**
 * System.out.println(DateTimeFormatter.BASIC_ISO_DATE.format(zonedDateTime));         // 20190126+0100
 * System.out.println(DateTimeFormatter.ISO_LOCAL_DATE.format(zonedDateTime));         // 2019-01-26
 * System.out.println(DateTimeFormatter.ISO_OFFSET_DATE.format(zonedDateTime));        // 2019-01-26+01:00
 * System.out.println(DateTimeFormatter.ISO_DATE.format(zonedDateTime));               // 2019-01-26+01:00
 * System.out.println(DateTimeFormatter.ISO_LOCAL_TIME.format(zonedDateTime));         // 10:15:30
 * System.out.println(DateTimeFormatter.ISO_OFFSET_TIME.format(zonedDateTime));        // 10:15:30+01:00
 * System.out.println(DateTimeFormatter.ISO_TIME.format(zonedDateTime));               // 10:15:30
 * System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(zonedDateTime));    // 2019-01-26T10:15:30
 * System.out.println(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(zonedDateTime));   // 2019-01-26T10:15:30+01:00
 * System.out.println(DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime));    // 2019-01-26T10:15:30+01:00[Europe/Paris]
 * System.out.println(DateTimeFormatter.ISO_DATE_TIME.format(zonedDateTime));          // 2019-01-26T10:15:30+01:00[Europe/Paris]
 * System.out.println(DateTimeFormatter.ISO_ORDINAL_DATE.format(zonedDateTime));       // 2019-026+01:00
 * System.out.println(DateTimeFormatter.ISO_WEEK_DATE.format(zonedDateTime));          // 2019-W04-6+01:00
 * System.out.println(DateTimeFormatter.ISO_INSTANT.format(zonedDateTime));            // 2019-01-26T09:15:30Z
 * System.out.println(DateTimeFormatter.RFC_1123_DATE_TIME.format(zonedDateTime));     // Sat, 26 Jan 2019 10:15:30 +0100
 *
 * @Description: java8 时间工具
 * @Date: 2019-05-29
 * @author: luowuhui
 */
public class LocalDateUtil {
	public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
	public static final ZoneId            zone                = ZoneId.systemDefault();
	public static final ZoneOffset        zoneOffset          = ZoneOffset.ofHours(8);


	/**
	 * 将 yyyy-MM-dd HH:mm:ss 转换为 Date
	 *
	 * @param strDate
	 * @return
	 */
	public static LocalDateTime strToDate (@NotNull String strDate) {
		return LocalDateTime.parse(strDate,DATE_TIME_FORMATTER);
	}


	/**
	 * 将指定格式时间字符串转换为 Date
	 *
	 * @param strDate
	 * @return
	 */
	public static LocalDateTime strToDate (@NotNull String strDate,@NotNull DateTimeFormatter dateTimeFormatter) {
		return LocalDateTime.parse(strDate,dateTimeFormatter);
	}


	/**
	 * 将 Date 转换为 yyyy-MM-dd HH:mm:ss
	 */
	public static String dateToStr (@NotNull TemporalAccessor date) {
		return DATE_TIME_FORMATTER.format(date);
	}


	/**
	 * 将 Date 转换为 yyyy-MM-dd HH:mm:ss
	 */
	public static String dateToStr (@NotNull DateTimeFormatter dateTimeFormatter,@NotNull TemporalAccessor date) {
		return dateTimeFormatter.format(date);
	}

	public static Date getDate (@NotNull LocalDateTime date) {
		Instant instant = date.atZone(zone)
		                      .toInstant();
		return Date.from(instant);
	}

	/**
	 * 将LocalDateTime转Date
	 *
	 * @param date
	 * @return Date
	 */
	public static Date lDateToDate (@NotNull LocalDateTime date) {
		Instant instant = date.atZone(zone)
		                      .toInstant();
		return Date.from(instant);
	}

	/**
	 * 将Datee转LocalDateTime
	 *
	 * @param date 非空时间对象
	 * @return LocalDateTime
	 */
	public static LocalDateTime dateToLDate (@NotNull Date date) {
		Instant instant = date.toInstant();
		return LocalDateTime.ofInstant(instant,zone);
	}


	/**
	 * 将毫秒时间戳转LocalDateTime
	 *
	 * @param timestamp 毫秒
	 * @return LocalDateTime
	 */
	public static LocalDateTime timestampToDate (@NotNull long timestamp) {
		return Instant.ofEpochMilli(timestamp)
		              .atZone(zone)
		              .toLocalDateTime();
	}


	/**
	 * 将毫秒时间戳转yyyy-MM-dd HH:mm:ss格式字符串
	 *
	 * @param timestamp 毫秒
	 * @return LocalDateTime
	 */
	public static String timestampToStr (@NotNull long timestamp) {
		return dateToStr(timestampToDate(timestamp));
	}


	/**
	 * 将毫秒时间戳转yyyy-MM-dd HH:mm:ss格式字符串
	 *
	 * @param timestamp 毫秒
	 * @return LocalDateTime
	 */
	public static String timestampToStr (long timestamp,@NotNull DateTimeFormatter dateTimeFormatter) {
		return dateToStr(dateTimeFormatter,timestampToDate(timestamp));
	}


	/**
	 * 时间转时间戳(毫秒)
	 *
	 * @param localDateTime
	 * @return
	 */
	public static long dateToTimestamp (@NotNull LocalDateTime localDateTime) {
		return localDateTime.toInstant(zoneOffset)
		                    .toEpochMilli();
	}

	/**
	 * 时间转时间戳(毫秒)
	 *
	 * @param localDate
	 * @return
	 */
	public static long dateToTimestamp (@NotNull LocalDate localDate) {
		return dateToTimestamp(localDate.atStartOfDay());
	}


	/**
	 * 时间字符串yyyy-MM-dd HH:mm:ss转时间戳
	 *
	 * @param strDate
	 * @return
	 */
	public static long strToTimestamp (@NotNull String strDate) {

		return dateToTimestamp(strToDate(strDate));
	}

	/**
	 * 指定格式时间字符串转时间戳(毫秒)
	 *
	 * @param strDate
	 * @return
	 */
	public static long strToTimestamp (@NotNull String strDate,@NotNull DateTimeFormatter dateTimeFormatter) {

		return dateToTimestamp(strToDate(strDate,dateTimeFormatter));
	}

	/**
	 * 时间转时间戳(秒)
	 *
	 * @param localDate
	 * @return
	 */
	public static long dateToTimestampSeconds (@NotNull LocalDate localDate) {
		return dateToTimestamp(localDate.atStartOfDay()) / 1000L;
	}

	/**
	 * 时间转时间戳(秒)
	 *
	 * @param localDateTime
	 * @return
	 */
	public static long dateToTimestampSeconds (@NotNull LocalDateTime localDateTime) {
		return dateToTimestamp(localDateTime) / 1000L;
	}

	/**
	 * 时间字符串yyyy-MM-dd HH:mm:ss转时间戳(秒)
	 *
	 * @param strDate
	 * @return
	 */
	public static long strToTimestampSeconds (@NotNull String strDate) {

		return dateToTimestamp(strToDate(strDate)) / 1000L;
	}

	/**
	 * 指定格式时间字符串转时间戳(秒)
	 *
	 * @param strDate
	 * @return
	 */
	public static long strToTimestampSeconds (@NotNull String strDate,@NotNull DateTimeFormatter dateTimeFormatter) {

		return dateToTimestamp(strToDate(strDate,dateTimeFormatter)) / 1000L;
	}


	/**
	 * 时间计算
	 *
	 * @param now 开始时间 , not null
	 * @param end 结束时间,not null
	 * @return
	 */
	public static Duration between (@NotNull LocalDateTime now,@NotNull LocalDateTime end) {
		return Duration.between(now,end);
	}


	/**
	 * 获取当前天的开始时间戳(毫秒)
	 *
	 * @return
	 */
	public static long currentDayStartTimestamp () {
		return dateToTimestamp(LocalDate.now());
	}

	/**
	 * 获取指定天前的开始时间戳(毫秒)
	 * 正数为当前时间之后,负数为当前时间之前
	 *
	 * @return
	 */
	public static long assignDayBeforeStartTimestamp (int day) {
		return dateToTimestamp(LocalDate.now()
		                                .plusDays(day));
	}

	/**
	 * 获取指定天前的结束时间戳(毫秒)
	 * 正数为当前时间之后,负数为当前时间之前
	 *
	 * @return
	 */
	public static long assignDayBeforeEndTimestamp (int day) {
		return assignDayBeforeStartTimestamp(day + 1) - 1L;
	}

	/**
	 * 获取当前天周的开始时间戳(毫秒)
	 *
	 * @return
	 */
	public static long currentWeekStartTimestamp () {
		return assignWeekBeforeStartTimestamp(0);
	}

	/**
	 * 获取指定周前的开始时间戳(毫秒)
	 * 正数为当前时间之后,负数为当前时间之前
	 *
	 * @return
	 */
	public static long assignWeekBeforeStartTimestamp (int week) {

		int value = LocalDate.now()
		                     .getDayOfWeek()
		                     .getValue();
		LocalDate localDate = LocalDate.now()
		                               .minusDays(value);
		int dayWeek = week * 7;
		return dateToTimestamp(localDate.plusDays(dayWeek));
	}

	/**
	 * 获取指定周前的结束时间戳(毫秒)
	 * 正数为当前时间之后,负数为当前时间之前
	 *
	 * @return
	 */
	public static long assignWeekBeforeEndTimestamp (int week) {
		return assignWeekBeforeStartTimestamp(week + 1) - 1L;
	}

	/**
	 * 获取当前天月的开始时间戳(毫秒)
	 *
	 * @return
	 */
	public static long currentMonthStartTimestamp () {
		return assignMonthBeforeStartTimestamp(0);
	}

	/**
	 * 获取指定周前的开始时间戳(毫秒)
	 * 正数为当前时间之后,负数为当前时间之前
	 *
	 * @return
	 */
	public static long assignMonthBeforeStartTimestamp (int month) {
		int dayOfMonth = LocalDate.now()
		                          .getDayOfMonth();
		LocalDate localDate = LocalDate.now()
		                               .minusDays(dayOfMonth);
		return dateToTimestamp(localDate.plusMonths(month));
	}

	/**
	 * 获取指定周前的结束时间戳(毫秒)
	 * 正数为当前时间之后,负数为当前时间之前
	 *
	 * @return
	 */
	public static long assignMonthBeforeEndTimestamp (int month) {
		return assignMonthBeforeStartTimestamp(month + 1) - 1L;
	}

	/**
	 * 获取当前天的开始时间戳(毫秒)
	 *
	 * @return
	 */
	public static long currentDayEndTimestamp () {
		return dateToTimestamp(LocalDate.now()
		                                .plusDays(1)) - 1L;
	}

	/**
	 * 获取当前天周的开始时间戳(毫秒)
	 *
	 * @return
	 */
	public static long currentWeekEndTimestamp () {
		return assignWeekBeforeEndTimestamp(0);
	}

	/**
	 * 获取当前天月的开始时间戳(毫秒)
	 *
	 * @return
	 */
	public static long currentMonthEndTimestamp () {
		return assignMonthBeforeEndTimestamp(0);
	}
}
